import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;

import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.script.Constants;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.RSInterface;
import com.speljohan.rsbot.script.wrappers.RSInterfaceChild;
import com.speljohan.rsbot.script.wrappers.RSObject;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class LumbFlaxSpinner extends Script implements PaintListener {

	private final int BANK_ID = 36786;
	private final RSTile CLOSED_DOOR = new RSTile(3207, 3214);
	public int expOnStart;
	private final int FLAX_ID = 1779;
	private final int SPIN_INTER_ID = 459;
	private final RSTile STAIRS = new RSTile(3205, 3208);
	public long startTime;
	private final int STRING_CHILD_ID = 17;
	private int tries;
	int tries2;
	private final int WHEEL_ID = 36970;

	public boolean atSpellInterface(final int spell, final String actionContains) {
		final RSInterfaceChild i = RSInterface.getChildInterface(192, spell);
		if (!i.isValid()) {
			return false;
		}
		final Rectangle pos = i.getArea();
		if (pos.x == -1 || pos.y == -1 || pos.width == -1 || pos.height == -1) {
			return false;
		}
		moveMouse((int) random(pos.getMinX(), pos.getMaxX()), (int) random(pos
				.getMinY(), pos.getMaxY()));
		clickMouse(true);
		return true;
	}

	public boolean castSomeSpell(int spell) {
		if (getCurrentTab() != Constants.TAB_MAGIC) {
			openTab(Constants.TAB_MAGIC);
			return false;
		}
		if (spell == 19) {
			spell = 60;
		} else if (spell == 61) {
			spell = 63;
		} else if (spell >= 30) {
			spell--;
		}
		if (spell >= 64) {
			return false;
		}
		if (!RSInterface.getInterface(192).isValid()) {
			return false;
		}
		return atSpellInterface(spell, "cast");
	}

	@Override
	public String getAuthor() {
		return "Alowaniak";
	}

	@Override
	public String getName() {
		return "Lumby Flax Spinner";
	}

	@Override
	public String getScriptCategory() {
		return "Crafting";
	}

	@Override
	public double getVersion() {
		return 1.0;
	}

	public boolean goTo(RSTile t, final int range) { // New walking method by
		// Bug5532.
		if (distanceTo(t) < range) {
			return true;
		}

		if (distanceTo(t) < 13) {
			walkTileMM(t);
			wait(random(500, 1000));
			return false;
		}

		while (true) {
			t = new RSTile((t.getX() + getMyPlayer().getLocation().getX()) / 2
					+ random(-1, 1), (t.getY() + getMyPlayer().getLocation()
					.getY())
					/ 2 + random(-1, 1));
			if (distanceTo(t) < 15) {
				walkTileMM(t);
				wait(random(500, 1000));
				break;
			}
		}
		return false;
	}

	public boolean isBusy() {
		final boolean busy = false;
		for (int i = 0; i < 12; i++) {
			if (getMyPlayer().getAnimation() != -1 || getMyPlayer().isMoving()) {
				return true;
			}
			wait(random(99, 100));
		}
		return busy;
	}

	@Override
	public int loop() {
		try {
			if (expOnStart == 0) {
				expOnStart = skills.getCurrentSkillExp(Constants.STAT_CRAFTING);
			}
			if (RSInterface.getInterface(109).isValid()) {
				walkTileMM(getLocation());
			}

			if (getEnergy() >= random(50, 75)) {
				setRun(true);
			}

			if (getMyPlayer().isMoving()) {
				return random(100, 200);
			}

			if (tries >= 5) {
				log("Seems like we're out of flax, stopping script.");
				stopAllScripts();
			}

			if (getMyPlayer().isInCombat()) {
				if (getPlane() == 1) {
					if (canReach(STAIRS, true)) {
						if (!tileOnScreen(new RSTile(STAIRS.getX() - 1, STAIRS
								.getY()))) {
							walkTileMM(STAIRS);
						} else {
							atTile(STAIRS, "up");
						}
					} else {
						openDoor(getObjectAt(CLOSED_DOOR));
					}
					return random(300, 600);
				} else if (getPlane() == 2) {
					if (!tileOnScreen(STAIRS)) {
						walkTileMM(STAIRS);
					} else {
						atTile(STAIRS, "down");
					}
					return random(300, 600);
				}
			}

			if (getPlane() == 1 && distanceTo(new RSTile(3220, 3218)) <= 40) { // Plane
				// is
				// 1
				// so
				// we
				// are
				// at
				// the
				// spinning
				// wheel
				if (getInventoryCount(FLAX_ID) >= 1) { // We've got flax
					if (RSInterface.getInterface(SPIN_INTER_ID).isValid()) {
						atInterface(SPIN_INTER_ID, STRING_CHILD_ID, "all");
					} else {
						final RSObject door = getObjectAt(CLOSED_DOOR);
						if (door != null) {
							if (!isBusy()) {
								openDoor(door);
							}
						} else {
							final RSObject wheel = findObject(WHEEL_ID);
							if (!tileOnScreen(wheel.getLocation())) {
								walkTileMM(new RSTile(3209, 3213));
							} else {
								if (distanceTo(wheel.getLocation()) >= 2) {
									atObject(wheel, "spin");
								} else if (!isBusy()
										&& getInventoryCount(FLAX_ID) >= 1) {
									setCameraAltitude(true);
									atObject(wheel, "spin");
								}
							}
						}
					}
				} else { // We haven't got flax
					if (RSInterface.getInterface(SPIN_INTER_ID).isValid()) {
						walkTileMM(STAIRS);
					}
					if (canReach(STAIRS, true)) {
						if (!tileOnScreen(new RSTile(STAIRS.getX() - 1, STAIRS
								.getY()))) {
							walkTileMM(STAIRS);
						} else {
							atTile(STAIRS, "up");
						}
					} else {
						openDoor(getObjectAt(CLOSED_DOOR));
					}
				}
			} else if (getPlane() == 2
					&& distanceTo(new RSTile(3220, 3218)) <= 40) { // Plane is 2
				// so we are
				// at the
				// bank.
				if (getInventoryCount(FLAX_ID) >= 1) {
					if (!tileOnScreen(STAIRS)) {
						walkTileMM(STAIRS);
					} else {
						atTile(STAIRS, "down");
					}
				} else {
					if (bank.getInterface().isValid()) {
						bank.depositAllExcept(FLAX_ID);
						if (!withdrawFlax()) {
							tries++;
						} else {
							tries = 0;
						}
					} else {
						final RSObject bankBooth = findObject(BANK_ID);
						if (!tileOnScreen(bankBooth.getLocation())) {
							walkTileMM(bankBooth.getLocation());
						} else {
							atObject(bankBooth, "Use-quickly");
						}
					}
				}
			} else { // 1 > Plane > 2, So lost
				if (distanceTo(new RSTile(3220, 3218)) >= 40) {
					if (isLoggedIn()) {
						openTab(Constants.TAB_MAGIC);
						wait(random(500, 1000));
						castSomeSpell(0);
						wait(random(3000, 4000));
						if (getMyPlayer().getAnimation() != -1) {
							tries2 = 0;
							return random(20000, 22000);
						} else if (tries2 <= 8) {
							tries2++;
							return random(1000, 3000);
						}
						log("Got lost and couldn't do home tele.");
						log("Will stop script now.");
						stopAllScripts();
						return -1;
					}
				} else {
					if (!tileOnScreen(new RSTile(STAIRS.getX() - 1, STAIRS
							.getY()))) {
						goTo(STAIRS, 1);
					} else {
						atTile(new RSTile(STAIRS.getX() - 1, STAIRS.getY()),
								"up");
					}
				}
			}
		} catch (final Exception e) {
			e.printStackTrace();
			log("Some bug... trying to continue");
			return random(3000, 4000);
		}
		return random(400, 600);
	}

	@Override
	public void onFinish() {
		Bot.getEventManager().removeListener(this);
	}

	@Override
	public void onRepaint(final Graphics g) {
		// TODO Auto-generated method stub
		if (isLoggedIn()) {
			g.setColor(Color.RED);
			long millis = System.currentTimeMillis() - startTime;
			final long hours = millis / 1000 / 60 / 60;
			millis -= hours * 1000 * 60 * 60;
			final long minutes = millis / 1000 / 60;
			millis -= minutes * 1000 * 60;
			final long seconds = millis / 1000;
			final long aminutes = minutes + hours * 60;

			final int exp = skills.getCurrentSkillExp(Constants.STAT_CRAFTING);
			final int expNext = skills
					.getXPToNextLevel(Constants.STAT_CRAFTING);

			final int stringMade = (exp - expOnStart) / 15;

			final int x = 310;
			int y = 360;

			g.drawString("Time running: " + hours + ":" + minutes + ":"
					+ seconds, x, y);
			y += 15;
			g.drawString("Strings made: " + stringMade, x, y);
			y += 15;
			g.drawString("Exp gained: " + (exp - expOnStart), x, y);
			y += 15;
			g.drawString("Exp till next level: " + expNext, x, y);
			y += 15;
			g.drawString("Strings till next level: " + expNext / 15, x, y);
			y += 15;
			if (aminutes >= 1 && stringMade >= 1) {
				final long alchsPerMinute = stringMade / aminutes;
				final long expPerMinute = stringMade * 15 / aminutes;
				g.drawString("Spins/hour: " + alchsPerMinute * 60
						+ "    Spins/minute: " + alchsPerMinute, x, y);
				y += 15;
				g.drawString("Exp/hour: " + expPerMinute * 60
						+ "   Exp/minute: " + expPerMinute, x, y);
				y += 15;
				long minutesTill = expNext / expPerMinute;
				final long hoursTill = minutesTill / 60;
				minutesTill -= hoursTill * 60;
				g.drawString("Est. time till next level: " + hoursTill + ":"
						+ minutesTill, x, y);
			}
		}
	}

	@Override
	public boolean onStart(final String[] args) {
		expOnStart = 0;
		tries = 0;
		tries2 = 0;
		startTime = System.currentTimeMillis();
		return true;
	}

	public void openDoor(final RSObject door) {
		walkTileMM(door.getLocation());
		setCameraRotation(random(40, 141));
		atDoor(door, "n", "open");
	}

	public boolean withdrawFlax() {
		final Point p = new Point(55 + random(-5, 6), 105 + random(-5, 6));
		clickMouse(p, false);
		return atMenu("one F");
	}
}